package com.vehicle.service.remote.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
import com.alibaba.fastjson2.JSONObject;
import com.vehicle.biz.cache.AccessTokenCache;
import com.vehicle.domains.dto.AccessTokenDto;
import com.vehicle.domains.dto.BaseResponse;
import com.vehicle.domains.entity.CommonVehicleEntity;
import com.vehicle.domains.entity.TransportVehicleEntity;
import com.vehicle.enums.EmissionStandardEnum;
import com.vehicle.exception.VehicleAccessException;
import com.vehicle.service.config.SystemConfig;
import com.vehicle.service.config.SystemConfigService;
import com.vehicle.service.remote.TjRemoteService;
import com.vehicle.utils.Base64ToImageUtil;
import com.vehicle.utils.VehicleStringUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.charset.StandardCharsets;

@Service
@Slf4j
public class TjRemoteServiceImpl implements TjRemoteService {

    @Resource
    private SystemConfigService systemConfigService;

    @Resource
    private AccessTokenCache accessTokenCache;

    @Override
    public AccessTokenDto getAccessToken(String username, String password) throws IOException {
        JSONObject jsonObject = new JSONObject();
        long requestTime = System.currentTimeMillis();
        jsonObject.put("username", username);
        jsonObject.put("password", SmUtil.sm3().digestHex(username+requestTime+password));
        jsonObject.put("requestTime", requestTime);
        jsonObject.put("encrypt_method", 2);

        return requestHandle(jsonObject,AccessTokenDto.class,"/api/v1/vehicleInfo");
    }

    private <T> T  requestHandle(JSONObject jsonObject,Class<T> clazz,String url) throws IOException {
        OkHttpClient client = new OkHttpClient();
        MediaType mediaType = MediaType.parse("application/json; charset=utf-8");
        RequestBody body = RequestBody.create(jsonObject.toJSONString(),mediaType);
        // 打印请求参数,过滤掉打印日志中照片的Base64的编码消息
        log.info("[tj远程请求参数 {}] params:{}", url, VehicleStringUtil.toNonBase64JsonString(jsonObject));
        Request request = new Request.Builder()
                .url(systemConfigService.get(SystemConfig.tjDovEndpoint)+url)
                .post(body)
                .build();
        try(Response response = client.newCall(request).execute()){
            if (!response.isSuccessful() || response.body() == null) {
                throw VehicleAccessException.NET_ERROR.newInstance("远程调用tj接口失败");
            }
            String responseBody = response.body().string();
            // 打印响应结果
            log.info("[tj远程请求响应 {}] result:{}", url,VehicleStringUtil.toNonBase64JsonString(responseBody));
            return JSONObject.parseObject(responseBody, clazz);
        }
    }

    /**
     * 上报车辆注册登记信息至天津监管平台
     * <p>
     * 将普通车辆与运输车辆的基本信息组装为 JSON 数据，
     * 使用 SM2 公钥加密后通过远程接口上报至监管平台。
     * 同时上传相关行驶证、许可证图片。
     * </p>
     * @return
     */
    public BaseResponse putRegisterVehicleInfo(CommonVehicleEntity commonVehicleEntity, TransportVehicleEntity transportVehicleEntity) throws IOException {
        //组装数据
        JSONObject data = new JSONObject();
        // 设置车牌号、颜色、类型、发动机等基础字段
        data.put("plateNo", commonVehicleEntity.getVehicleNumber());
        data.put("plateColor", commonVehicleEntity.getVehiclePlateColor());
        data.put("vehicleType", transportVehicleEntity.getTransportVehicleType());
        data.put("vin", commonVehicleEntity.getVin());
        data.put("engineNo", transportVehicleEntity.getEngineNo());
        data.put("registerDate", DateUtil.format(commonVehicleEntity.getExpireTime(), DatePattern.PURE_DATE_FORMAT));
        data.put("vehicleBrand", transportVehicleEntity.getVehicleBrand());
        data.put("vehicleModel", transportVehicleEntity.getVehicleModel());
        data.put("fuelType", transportVehicleEntity.getFuelType());
        data.put("engineType", transportVehicleEntity.getEngineType());
        data.put("engineManufacturer", transportVehicleEntity.getEngineManufacturer());
        data.put("emissionStandard", EmissionStandardEnum.valueOf(transportVehicleEntity.getEmissionStandard()).getCode());
        data.put("connectedStatus", transportVehicleEntity.getNetworkStatus());
        data.put("useCharacter", transportVehicleEntity.getUsageNature());
        data.put("owner", commonVehicleEntity.getOwnerName());

        //使用sm2公钥加密
        String publicKey = getPublicKey();
        SM2 sm2 = SmUtil.sm2(null,publicKey);
        String value = sm2.encryptHex(data.toJSONString(), StandardCharsets.UTF_8, KeyType.PublicKey);

        String accessToken = getAccessToken();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("access_token", accessToken);
        jsonObject.put("company_code", systemConfigService.get(SystemConfig.companyCode));
        jsonObject.put("encrypt_method", 2);
        // 转换许可证、行驶证图片为 Base64 编码并压缩处理
        jsonObject.put("envLicenseImg", Base64ToImageUtil.imageToBase64LimitSize(transportVehicleEntity.getAttachedListUrl()));
        jsonObject.put("drivingLicenseImg", Base64ToImageUtil.imageToBase64LimitSize(transportVehicleEntity.getDrivingLicenseUrl()));
        jsonObject.put("value", value);

        return requestHandle(jsonObject,BaseResponse.class,"/api/v1/vehicleInfo");
    }

    public String getAccessToken(){
        //先查询缓存中有没有
        AccessTokenDto accessTokenDto = accessTokenCache.get();
        if (accessTokenDto != null) {
            return accessTokenDto.getAccessToken();
        }

        //缓存中没有就重新获取
        try {
            AccessTokenDto accessToken = getAccessToken(systemConfigService.get(SystemConfig.companyUsername), systemConfigService.get(SystemConfig.companyPassword));
            //将获取到的数据缓存起来
            accessTokenCache.put(accessToken);
            return accessToken.getAccessToken();
        } catch (IOException e) {
            //记录错误日志
            log.error("获取tj接口token异常", e);
            throw VehicleAccessException.NET_ERROR.newInstance("获取token异常");
        }
    }

    public String getPublicKey(){
        //先查询缓存中有没有
        AccessTokenDto accessTokenDto = accessTokenCache.get();
        if (accessTokenDto != null) {
            return accessTokenDto.getPublicKey();
        }

        //缓存中没有就重新获取
        try {
            AccessTokenDto accessToken = getAccessToken(systemConfigService.get(SystemConfig.companyUsername), systemConfigService.get(SystemConfig.companyPassword));
            //将获取到的数据缓存起来
            accessTokenCache.put(accessToken);
            return accessToken.getPublicKey();
        } catch (IOException e) {
            //记录错误日志
            log.error("获取tj接口publicKey异常", e);
            throw VehicleAccessException.NET_ERROR.newInstance("获取publicKey异常");
        }
    }
}
